vlwkaos' digital garden

Rust - structs

고전적 형태의 struct

struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}
  • String은 String::from("asdf") 이렇게 해야 제대로 초기화된다.
  • struct내부값의 Ownership을 보장하기 위해서 참조만 받는 것은 안된다.

struct 변수 생성

fn build_user(email: String, username: String) -> User {
    User {
        email,
        username,
        active: true,
        sign_in_count: 1,
    }
}

Tuple 형태의 struct

fn main() {
    struct Color(i32, i32, i32);
    struct Point(i32, i32, i32);

    let black = Color(0, 0, 0);
    let origin = Point(0, 0, 0);
}

Unit Struct

struct UnitStruct;

Update Syntax

아래처럼 나머지 값을 채울 수 있음

struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

fn main() {
    let user1 = User {
        email: String::from("someone@example.com"),
        username: String::from("someusername123"),
        active: true,
        sign_in_count: 1,
    };

    let user2 = User {
        email: String::from("another@example.com"),
        username: String::from("anotherusername567"),
        ..user1
    };
}

struct::function == impl

  • struct와 동일한 이름으로 impl 구현을 하면 클래스 메소드처럼 작성이 된다.
  • 인자로 &self를 넘기면 오브젝트 자기 자신을 참조한다
  • 함수 이름을 new로 하면 Object::new() 이런식으로 호출 (오브젝트 생성 전이니까... 스태틱 형태로 함수를 사용 가능하다)
impl Package {
    fn new(sender_country: String, recipient_country: String, weight_in_grams: i32) -> Package {
        if weight_in_grams <= 0 {
            // Something goes here...
            panic!("oh no");
        } else {
            return Package {
                sender_country,
                recipient_country,
                weight_in_grams,
            };
        }
    }

    fn is_international(&self) -> bool {
        // Something goes here...
        self.sender_country != self.recipient_country
    }

    fn get_fees(&self, cents_per_gram: i32) -> i32 {
        // Something goes here...
        self.weight_in_grams * cents_per_gram
    }
}
  • namespace merging이 되므로 클래스 메소드와, 전역으로 사용할 함수를 분리해서 구현하는 경우가 권장된다.

Struct size

  • clippy 린터같은 역할
fn main() {

    let pop = 35_000_000;
    let cap = "Ottawa".to_string();
    let lead = "Justin Trudeau".to_string();
    let canada = Country {
        population: pop, // 똑같으면 redundant
    };

    // alignment modifiers. byte 개수가 나온다
    println!("asdf", mem::size_of_val(&canada));

    // 예를 들어 u8 세개(3바이트) u32(4바이트) 하나면 8개의 바이트로 공간이 만들어진다.
    // 코드 최적화할때...
    
}
  • 1 byte + 4byte => 4, 4
  • 1, 4, 1 => 12

destructuring

struct Person {
    name: String,
    real_name: String,
    height: u8,
    happiness: bool
}

struct Person2 {
    name: String,
    height: u8
}

impl Person2 {
    fn from_person(input: Person) -> Self {
        let Person {name,KE height, .. } = input;

        Self {
            name,
            height
        }
    }
}


fn main() {
    let papa_doc = Person {
        name: "Papa Doc".to_string(),
        real_name: "Clarence".to_string(),
        height: 170,
        happiness: false
    };

    // 아래는 너무 길다
    println!("They call him {} but his real name is {}. He is {} cm tall is he happy? {}", papa_doc.name, papa_doc.real_name, papa_doc.height, papa_doc.happiness);

    // destructuring
    let Person {name: a, real_name, height, happiness} = papa_doc;

    let p2 = Person2::from_person(papa_doc);
    
}

Referred in

Rust - structs